/****************************************************
	文件：ViewBase.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2021/1/14 13:25:42
	功能：视图层 基类
*****************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HTFW.Consts;
using HTFW.Core;
using HTFW.Res;
using HTFW.Utility.Runtime;
using EventType = HTFW.Core.EventType;
using IDisposable = HTFW.Core.IDisposable;

namespace HTFW.UI
{
    public class ViewBase : IDisposable
    {
        protected Transform mTransform;

        protected CanvasGroup mCanvasGroup;

        protected bool mHasInit;
        protected UILayer mUILayer;
        protected UIType mUIType;
        protected bool mVisible = true;

        protected string mPath;

        public Transform Transform => mTransform;
        public bool HasInit => mHasInit;
        public UILayer UILayer => mUILayer;
        public UIType UIType => mUIType;

        public bool Visible
        {
            get => mVisible;
            protected set
            {
                if (mVisible != value)
                {
                    mVisible = value;
                    if (mCanvasGroup != null)
                        mCanvasGroup.alpha = mVisible ? 1f : 0f;
                }
            }
        }

        public virtual void SetupUI() //子类需设置 UI 基础属性
        {
            mUILayer = UILayer.HUD;
            mUIType = UIType.Once;
        }


        //------------------------------ 生命周期（外部） ------------------------------//

        #region 生命周期（外部）

        public void InitSync(string path, bool isVisible)
        {
            SetupUI();

            if (mHasInit) return;

            mPath = path;

            mTransform = HTDriver.GlobalContext.ResContext.RPrefab
                .Instantiate(mPath, UIManager.Instance.GetUILayerTrans(mUILayer))
                .transform;

            mCanvasGroup = mTransform.gameObject.AddComponent<CanvasGroup>();

            RuntimeUtil.SetSortingOrder(mTransform.gameObject, mUILayer);

            Visible = isVisible;

            OnInit();

            mHasInit = true;
        }

        public void InitAsync(string path, bool isVisible, Action onCompleted)
        {
            SetupUI();

            if (mHasInit) return;

            mPath = path;

            HTDriver.GlobalContext.ResContext.RPrefab.PreloadAsync(mPath, ResTaskPriority.High, (obj) =>
            {
                mTransform = HTDriver.GlobalContext.ResContext.RPrefab
                    .Instantiate(mPath, UIManager.Instance.GetUILayerTrans(mUILayer))
                    .transform;

                RuntimeUtil.SetSortingOrder(mTransform.gameObject, mUILayer);

                Visible = isVisible;

                OnInit();

                mHasInit = true;

                onCompleted?.Invoke();
            });
        }

        public void Dispose()
        {
            if (mTransform != null)
            {
                HTDriver.GlobalContext.ResContext.RPrefab.Destroy(mTransform.gameObject, true);
                mTransform = null;
            }

            mHasInit = false;
        }

        public void Show()
        {
            Visible = true;
            AddEvent(EventType.UI_OnViewUpdate, p => { Update(); });
            OnShow();
        }

        public void Hide()
        {
            Visible = false;

            OnHide();

            DisposeEventTimerFrameCorou();
        }

        public void Close()
        {
            UIManager.Instance.CloseWindow(mPath);
        }

        #endregion


        //------------------------------ 生命周期（内部）） ------------------------------//

        #region 生命周期（内部）

        protected virtual void OnInit()
        {
        }

        protected virtual void OnShow()
        {
            //事件注册
        }

        protected virtual void OnHide()
        {
            //事件注销
        }

        protected virtual void Update()
        {
        }

        public virtual void OnWindowMessageReceive(UIMessageType msgType, params object[] args)
        {
        }

        #endregion


        //------------------------------ 帮助方法 ------------------------------//

        #region 内部帮助方法

        /// <summary>
        /// 内部事件集合
        /// </summary>
        Dictionary<EventType, List<HCallBack>> mEventDict = new Dictionary<EventType, List<HCallBack>>();

        /// <summary>
        /// 内部计时任务 Id 列表
        /// </summary>
        List<int> mTimeTaskIdLst = new List<int>();

        /// <summary>
        /// 内部帧任务 Id 列表
        /// </summary>
        List<int> mFrameTaskIdLst = new List<int>();

        /// <summary>
        /// 协程列表
        /// </summary>
        List<IRoutineHandle> mRoutineLst = new List<IRoutineHandle>();


        /// <summary>
        /// 注册事件（隐藏/关闭界面时自动注销）
        /// </summary>
        /// <param name="eventType"></param>
        /// <param name="callBack"></param>
        protected void AddEvent(EventType eventType, HCallBack callBack)
        {
            EventCenter.Subscribe(eventType, callBack);

            if (mEventDict.ContainsKey(eventType))
            {
                mEventDict[eventType].Add(callBack);
            }
            else
            {
                List<HCallBack> cbLst = new List<HCallBack>();
                cbLst.Add(callBack);
                mEventDict.Add(eventType, cbLst);
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="eventType"></param>
        /// <param name="p"></param>
        protected void Fire(EventType eventType, params object[] p)
        {
            EventCenter.Publish(eventType, p);
        }

        /// <summary>
        /// 计时任务（隐藏/关闭界面时自动销毁）
        /// </summary>
        /// <param name="callBack"></param>
        /// <param name="delayTime"></param>
        /// <param name="timeUnit"></param>
        /// <param name="loopCount"></param>
        protected void AddTimer(Action<int> callBack, double delayTime, TimeUnit timeUnit = TimeUnit.MilliSecond,
            int loopCount = 1)
        {
            mTimeTaskIdLst.Add(
                HTDriver.GlobalContext.TimerContext.AddTimeTask(callBack, delayTime, timeUnit, loopCount));
        }

        /// <summary>
        /// 帧任务（隐藏/关闭界面时自动销毁）
        /// </summary>
        /// <param name="callBack"></param>
        /// <param name="delayFrame"></param>
        /// <param name="loopCount"></param>
        protected void AddFrame(Action<int> callBack, int delayFrame, int loopCount = 1)
        {
            mFrameTaskIdLst.Add(HTDriver.GlobalContext.TimerContext.AddFrameTask(callBack, delayFrame, loopCount));
        }

        /// <summary>
        /// 开启协程（隐藏/关闭界面时自动销毁）
        /// </summary>
        /// <param name="routine"></param>
        protected void AddCoroutine(IEnumerator routine)
        {
            mRoutineLst.Add(CoroutineService.Instance.Start(routine, true));
        }

        /// <summary>
        /// 注销内部事件/计时任务/帧任务/协程
        /// </summary>
        void DisposeEventTimerFrameCorou()
        {
            foreach (var item in mTimeTaskIdLst)
                HTDriver.GlobalContext.TimerContext.RemoveTimeTask(item);

            foreach (var item in mFrameTaskIdLst)
                HTDriver.GlobalContext.TimerContext.RemoveFrameTask(item);

            foreach (var item in mEventDict)
            {
                foreach (var cb in item.Value)
                    EventCenter.Unsubscribe(item.Key, cb);
            }

            foreach (var item in mRoutineLst)
                item.Stop();

            mTimeTaskIdLst.Clear();
            mFrameTaskIdLst.Clear();
            mEventDict.Clear();
            mRoutineLst.Clear();
        }

        #endregion
    }
}